package com.flying.sample.config;

import com.flying.acls.adapter.spring.AclBasedConfig.UrlConfig;
import com.flying.sample.handler.LoginSuccessHandler;
import com.flying.um.adapter.spring.SpringUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

@Configuration
//@EnableWebSecurity
public class WebSecurityConfig {
    @Order(1)
    @Configuration
    @ConditionalOnBean({AccessDecisionManager.class, FilterInvocationSecurityMetadataSource.class})
    @Import(UrlConfig.class)
    public static class AclBasedConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private AccessDecisionManager accessDecisionManager;
        @Autowired
        private FilterInvocationSecurityMetadataSource securityMetadataSource;

        @Override
        protected AuthenticationManager authenticationManager() throws Exception {
            return super.authenticationManager();
        }

        // do not create as a bean. or it will inject as a application filter too.(double injection.)
        private FilterSecurityInterceptor filterSecurityInterceptor() throws Exception {
            FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
            filterSecurityInterceptor.setSecurityMetadataSource(securityMetadataSource);
            filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
            filterSecurityInterceptor.setAuthenticationManager(authenticationManager());
            filterSecurityInterceptor.setRejectPublicInvocations(true);
            return filterSecurityInterceptor;
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/api/**")
                    .addFilter(filterSecurityInterceptor())
                    .formLogin();
        }
    }

    @Configuration
    public static class CommonConfig extends WebSecurityConfigurerAdapter {
        @Bean
        public LoginSuccessHandler loginSuccessHandler() {
            return new LoginSuccessHandler();
        }

        @Bean
        public PasswordEncoder passwordEncoder() {
            return NoOpPasswordEncoder.getInstance();
        }

        @Bean
        @Override
        protected UserDetailsService userDetailsService() {
            return new SpringUserDetailsService();
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/**/*.js", "/**/*.map");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .httpBasic()
                    .and()
                    .authorizeRequests()
                    .antMatchers("index.html", "/", "/home", "/login").permitAll()
//                    .anyRequest().permitAll()
                    .anyRequest().authenticated()
                    .and().csrf()
                    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());


//            http
//
//                    .authorizeRequests()
//                    .antMatchers("/home").permitAll()
//                    .antMatchers("/hello").hasAnyAuthority("ROLE_ADMIN", "ROLE_DREAM")
//                    .anyRequest().authenticated();
//                    .and().formLogin().loginPage("/login").permitAll();
//                    .successHandler(loginSuccessHandler())
//                    .and().logout().logoutSuccessUrl("/home").invalidateHttpSession(true)
//                    .and().rememberMe().tokenValiditySeconds(30 * 60);
//            http.authorizeRequests()
//                    .antMatchers("/**/*").permitAll();
            // support h2-console.
//            http.csrf().disable();
//            http.headers().frameOptions().disable();
        }
    }
}